package com.moliku.insurance.process.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.moliku.insurance.common.constant.CompanyEnum;
import com.moliku.insurance.common.constant.InsureStatusEnum;
import com.moliku.insurance.common.constant.OrderEnum;
import com.moliku.insurance.common.constant.PolicyConfigKeyEnum;
import com.moliku.insurance.common.response.CommonInsureResult;
import com.moliku.insurance.common.util.ByteUtils;
import com.moliku.insurance.model.dto.CancelInsureDTO;
import com.moliku.insurance.model.dto.DownloadInsureDTO;
import com.moliku.insurance.model.dto.insure.InsureDTO;
import com.moliku.insurance.model.dto.insure.InsuredInfoDTO;
import com.moliku.insurance.model.entity.Order;
import com.moliku.insurance.model.entity.OrderDetail;
import com.moliku.insurance.model.entity.liberty.*;
import com.moliku.insurance.process.mapper.BaseOrderMapper;
import com.moliku.insurance.process.mapper.LibertyMapper;
import com.moliku.insurance.process.strategy.PolicyStrategy;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 利宝
 *
 * @author Mr.Liu
 * @since 2021/2/5
 */
@Slf4j
@Service("LibertyService")
@AllArgsConstructor
public class LibertyServiceImpl implements PolicyStrategy {

    private final RestTemplate restTemplate;

    private final LibertyMapper mapper;
    private final BaseOrderMapper baseOrderMapper;
    private final ConfigServiceImpl configService;

    @Override
    public CommonInsureResult submitPolicy(InsureDTO request) {
        //判断当前订单是否为空
        Order order = baseOrderMapper.selectById(request.getLocalOrderId());
        if (null == order) {
            log.info("利宝投保失败,未查询到该订单:{}", request.getLocalOrderId());
            return CommonInsureResult.submitPolicyFail(InsureStatusEnum.INSURE_FAIL_5102);
        }
        //相应渠道编码
        String code;
        if (ObjectUtil.isNotEmpty(request.getOrder().getChannel2Code())) {
            code = request.getOrder().getChannel2Code();
        } else {
            code = request.getOrder().getChannel1Code();
        }
        String submitUrl = configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
        LibertyEntity libertyEntity = new LibertyEntity();
        libertyEntity.setPartnerAccountCode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.PARTNER_ACCOUNT_CODE));
        libertyEntity.setFlowId("");
        libertyEntity.setOperatorDate(DateUtil.format(DateUtil.date(), "yyyy-MM-dd hh:mm:ss"));

        //请求json
        LibertyRequestJson requestJson = new LibertyRequestJson();
        requestJson.setSequenceId(request.getOrder().getSerialNumber());
        //   客户ID 账号密码 操作人员ID
        requestJson.setConsumerId(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.CONSUMER_ID));
        requestJson.setUsercode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.USER_CODE));
        requestJson.setPassword(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.PASSWORD));
        requestJson.setOperateCode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.OPERATE_CODE));
        requestJson.setIsAutoUndwrt("1");
        requestJson.setRequestType(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.REQUEST_TYPE));
        //数据列表
        PolicyDataDto policyDataDto = new PolicyDataDto();
        List<PolicyDataDto.LibInsuresDto> insuredItemProcutDtoList = new ArrayList<>();
        //条款计划
        //保单公共信息
        PolicyDataDto.MainHeadDto mainHeadDto = new PolicyDataDto.MainHeadDto();
        mainHeadDto.setBussFromNo(request.getOrder().getSerialNumber());
        //语言 币种
        mainHeadDto.setLanguage("C");
        mainHeadDto.setCurrency("CNY");
        mainHeadDto.setRiskCode("2726");
        mainHeadDto.setArgueSolution("1");
        mainHeadDto.setDepartureCountry("CNH");
        mainHeadDto.setDepartureCountryName("中国大陆");
        if (ObjectUtil.isEmpty(request.getOrder().getDestination())) {
            mainHeadDto.setArrivalCountry("CHN");
            mainHeadDto.setArrivalCountryName("中国大陆");
        } else {
            mainHeadDto.setArrivalCountry("CHN");
            mainHeadDto.setArrivalCountryName(request.getOrder().getDestination());
        }
        policyDataDto.setMainHeadDto(mainHeadDto);
        //代理人销售信息
        PolicyDataDto.AgentDto agentDto = new PolicyDataDto.AgentDto();
        agentDto.setAgreementCode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.AGREEMENT_CODE));
        agentDto.setSalerName(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.SALER_NAME));
        agentDto.setSalerNumber(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.SALER_NUMBER));
        policyDataDto.setAgentDto(agentDto);

        //投保人信息
        PolicyDataDto.AppliDto appliDto = new PolicyDataDto.AppliDto();
        appliDto.setInsuredType("1");
        appliDto.setInsuredName(request.getPolicyHolder().getcName());
        appliDto.setInsuredEName(request.getPolicyHolder().geteName());
        appliDto.setIdentifyType(PolicyDataDto.map.get(request.getPolicyHolder().getCardType()));
        appliDto.setIdentifyNumber(request.getPolicyHolder().getCardNo());
        appliDto.setBirth(request.getPolicyHolder().getBirthDay());
        appliDto.setSex(request.getPolicyHolder().getSex().equals("0") ? "2" : "1");
        appliDto.setPayMth("7");
        policyDataDto.setAppliDto(appliDto);

        //被保险人信息
        List<InsuredInfoDTO> insureds = request.getInsureds();
        for (InsuredInfoDTO next : insureds) {
            PolicyDataDto.InsuredDto insuredDto = new PolicyDataDto.InsuredDto();
            //证件类型
            insuredDto.setIdentifyType(PolicyDataDto.map.get(String.valueOf(request.getPolicyHolder().getCardType())));
            insuredDto.setInsuredType("1");
            insuredDto.setInsuredName(next.getCName());
            insuredDto.setInsuredEName(next.getEName());
            insuredDto.setIdentifyNumber(next.getCardNo());
            insuredDto.setBirth(next.getBirthDay());
            insuredDto.setSex(next.getSex().equals("0") ? "2" : "1");
            insuredDto.setInsuredidentity("01");
            //受益方式
            insuredDto.setBenefType("0");
            PolicyDataDto.ProductDto productDto = new PolicyDataDto.ProductDto();
            productDto.setProductCode(request.getOrder().getProductCode());
            //设置条款信息与被保人信息
            PolicyDataDto.LibInsuresDto libInsuresDto = new PolicyDataDto.LibInsuresDto();
            libInsuresDto.setProductDto(productDto);
            libInsuresDto.setInsuredDto(insuredDto);
            insuredItemProcutDtoList.add(libInsuresDto);
        }

        //产品
        policyDataDto.setInsuredItemProcutDtoList(insuredItemProcutDtoList);
        // 保险期间信息
        PolicyDataDto.PeriodDto periodDto = new PolicyDataDto.PeriodDto();
        periodDto.setStartDate(DateUtil.format(DateUtil.parse(request.getOrder().getStartTime()), "yyyy-MM-dd"));
        periodDto.setEndDate(DateUtil.format(DateUtil.parse(request.getOrder().getEndTime()), "yyyy-MM-dd"));
        periodDto.setStartHour("0");
        periodDto.setEndHour("23");
        policyDataDto.setPeriodDto(periodDto);

        requestJson.setPolicyDataDto(policyDataDto);

        libertyEntity.setRequestJson(requestJson);
        //转为json字符串
        String jsonStr = JSONObject.toJSONString(libertyEntity);
        log.info("利宝投保参数:{}", jsonStr);
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        //获取本地库token
        String token;
        LibertyToken baseToken = mapper.selectByPrimaryKey(1);
        if (ObjectUtil.isEmpty(baseToken)) {
            token = getToken(code).getAccessToken();
        } else {
            token = baseToken.getAccessToken();
        }
        HttpEntity<String> httpEntity = new HttpEntity<>(jsonStr, headers);
        ResponseEntity<String> responseEntity = null;
        //发送请求
        try {
            responseEntity = restTemplate.postForEntity(submitUrl + token, httpEntity, String.class);
        } catch (HttpClientErrorException e) {
            log.info("token认证失败了!");
            token = refreshToken(code).getAccessToken();
            //发送请求
            responseEntity = restTemplate.postForEntity(submitUrl + token, httpEntity, String.class);
        }
        JSONObject jsonObject = JSONObject.parseObject(responseEntity.getBody());
        log.info("投保返回:{}", jsonObject);
        //保存返回结果
        OrderDetail orderDetail = baseOrderMapper.selectDeatailByOrderId(order.getId());
        orderDetail.setInsureRsp(responseEntity.getBody());
        baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);

        //结果集
        JSONObject result = jsonObject.getJSONObject("result");
        log.info("投保返回结果集result{}", result);
        //响应体
        JSONObject data = result.getJSONObject("responseJson");
        log.info("投保返回结果集data{}", data);
        try {
            if ("true".equals(data.getString("success"))) {
                order.setStatus(OrderEnum.CLOSED_NO_REFUND.getValue());
                order.setPolicyNo(data.getString("bussNewNo"));
                baseOrderMapper.updateById(order);
                log.info("投保成功!{}", jsonObject);
                return CommonInsureResult.submitPolicySuccess(data.getString("bussNewNo"));
            }
        } catch (Exception e) {
            log.info(e.getMessage());
            return CommonInsureResult.submitPolicyFail();
        }
        return CommonInsureResult.submitPolicyFail(data.getString("message"));

    }

    @Override
    public CommonInsureResult cancelPolicy(CancelInsureDTO request) {

        Order order = baseOrderMapper.selectByPolicyNo(request.getPolicyNo());
        if (null == order) {
            return CommonInsureResult.cancelPolicyFail(InsureStatusEnum.CANCEL_INSURE_FAIL_5202);
        }
        //请求地址
        String submitUrl = configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
        //退保所需信息
        LibertyEntity entity = new LibertyEntity();
        entity.setPartnerAccountCode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.PARTNER_ACCOUNT_CODE));
        entity.setFlowId("");
        entity.setOperatorDate(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss"));
        WithDrawBodyDto withDrawBodyDto = new WithDrawBodyDto();
        withDrawBodyDto.setPolicyNo(request.getPolicyNo());
        //TODO 日期偏移
        withDrawBodyDto.setValidDate(DateUtil.today());
        withDrawBodyDto.setValidHour(String.valueOf(DateUtil.hour(DateUtil.date(), true)));
        withDrawBodyDto.setCancelType("02");
        withDrawBodyDto.setEndorCause("01");
        withDrawBodyDto.setWithDrawPayMth("07");
        //退保
        LibertyRequestJson requestJson = new LibertyRequestJson();
        requestJson.setConsumerId(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.CONSUMER_ID));
        requestJson.setUsercode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.USER_CODE));
        requestJson.setPassword(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.PASSWORD));
        requestJson.setOperateCode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.OPERATE_CODE));
        requestJson.setRequestType("WITHDRAW");
        requestJson.setWithDrawBodyDto(withDrawBodyDto);
        entity.setRequestJson(requestJson);
        //请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        HttpEntity<String> httpEntity = new HttpEntity<>(JSONObject.toJSONString(entity), headers);
        log.info("退保参数:{}", JSONObject.toJSONString(entity));
        //发送退保请求
        //获取本地库token
        String token;
        LibertyToken baseToken = mapper.selectByPrimaryKey(1);
        if (ObjectUtil.isEmpty(baseToken)) {
            token = getToken(request.getChannelCode()).getAccessToken();
        } else {
            token = baseToken.getAccessToken();
        }
        //发送请求
        ResponseEntity<String> responseEntity = null;
        try {
            responseEntity = restTemplate.postForEntity(submitUrl + token, httpEntity, String.class);
        } catch (HttpClientErrorException e) {
            token = refreshToken(request.getChannelCode()).getAccessToken();
            responseEntity = restTemplate.postForEntity(submitUrl + token, httpEntity, String.class);
        }
        //返回值
        JSONObject jsonObject = JSONObject.parseObject(responseEntity.getBody());
        log.info("退保返回:{}", jsonObject);
        //保存返回结果
        OrderDetail orderDetail = baseOrderMapper.selectDeatailByOrderId(order.getId());
        orderDetail.setCancelPolicyRsp(responseEntity.getBody());
        baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);

        //结果集
        JSONObject result = jsonObject.getJSONObject("result");
        //响应体
        JSONObject data = result.getJSONObject("responseJson");
        if ("true".equals(data.getString("success"))) {
            //更改订单状态
            order.setStatus(OrderEnum.CANCEL.getValue());
            baseOrderMapper.updateById(order);
            return CommonInsureResult.cancelPolicySuccess();
        }
        return CommonInsureResult.cancelPolicyFail(data.getString("message"));
    }

    @Override
    public CommonInsureResult downloadPolicy(DownloadInsureDTO downloadInsure) {

        //获取本地库token
        String submitUrl = configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
        String token;
        LibertyToken baseToken = mapper.selectByPrimaryKey(1);
        if (ObjectUtil.isEmpty(baseToken)) {
            token = getToken(downloadInsure.getChannelCode()).getAccessToken();
        } else {
            token = baseToken.getAccessToken();
        }
        //下载保单
        LibertyEntity entity = new LibertyEntity();
        entity.setPartnerAccountCode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.PARTNER_ACCOUNT_CODE));
        entity.setFlowId("");
        entity.setOperatorDate(DateUtil.format(DateUtil.date(), "yyyy-MM-dd"));
        LibertyRequestJson requestJson = new LibertyRequestJson();
        requestJson.setConsumerId(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.CONSUMER_ID));
        requestJson.setUsercode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.USER_CODE));
        requestJson.setPassword(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.PASSWORD));
        requestJson.setOperateCode(configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.OPERATE_CODE));
        requestJson.setRequestType("REPRINT_FTP");
        requestJson.setBusinessNo(downloadInsure.getPolicyNo());
        requestJson.setPrintType("ecbUrl");
        entity.setRequestJson(requestJson);
        String str = JSONObject.toJSONString(entity);
        log.info("下载保单传输数据:{}", str);
        //请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        HttpEntity<String> httpEntity = new HttpEntity<>(JSONObject.toJSONString(entity), headers);
        //发送请求
        ResponseEntity<String> responseEntity = null;
        try {
            responseEntity = restTemplate.postForEntity(submitUrl + token, httpEntity, String.class);
        } catch (HttpClientErrorException e) {
            token = refreshToken(downloadInsure.getChannelCode()).getAccessToken();
            responseEntity = restTemplate.postForEntity(submitUrl + token, httpEntity, String.class);
        }
        JSONObject jsonObject = JSONObject.parseObject(responseEntity.getBody());
        log.info("利宝下载保单返回数据:{}", jsonObject);
        if (0 == jsonObject.getInteger("state") && (Boolean) jsonObject.get("success")) {
            //TODO 下载成功
            JSONObject result = jsonObject.getJSONObject("result");
            JSONObject data = result.getJSONObject("responseJson");
            String filePath = data.getString("filePath");
            log.info("利宝返回下载地址:{}", filePath);
            byte[] bytes = ByteUtils.urlToByte(filePath);
            return CommonInsureResult.downloadPolicySuccess(bytes);
        }
        return CommonInsureResult.downloadPolicyFail(jsonObject.getString("message"));
    }

    /**
     * 获取token接口
     *
     * @return
     */
    protected LibertyToken getToken(String code) {
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=utf-8");

        //获取密钥等信息
        MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
        requestBody.add("client_id", configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.CLIENT_ID));
        requestBody.add("client_secret", configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.CLIENT_SECRET));
        requestBody.add("username", configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.USERNAME));
        requestBody.add("password", configService.getConfigValue(CompanyEnum.LIBERTY, "tokenPassword"));
        requestBody.add("grant_type", "password");

        HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(requestBody, headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(configService.getConfigValue(CompanyEnum.LIBERTY, "tokenUrl"), requestEntity, String.class);
        JSONObject jsonObject = JSONObject.parseObject(responseEntity.getBody());
        LibertyToken libertyToken = JSON.toJavaObject(jsonObject, LibertyToken.class);
        LibertyToken base = mapper.selectByPrimaryKey(1);
        if (null == base) {
            mapper.insert(libertyToken);
        }
        return libertyToken;
    }

    /**
     * 刷新token接口
     *
     * @return
     */
    protected LibertyToken refreshToken(String code) {

        //本地库token
        LibertyToken libertyToken = mapper.selectByPrimaryKey(1);
        //请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=utf-8");
        //拼装请求参数
        MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
        requestBody.add("client_id", configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.CLIENT_ID));
        requestBody.add("client_secret", configService.getConfigValue(CompanyEnum.LIBERTY, PolicyConfigKeyEnum.CLIENT_SECRET));
        requestBody.add("refresh_token", libertyToken.getRefreshToken());
        requestBody.add("grant_type", "refresh_token");

        //请求对象
        HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(requestBody, headers);
        //发起调用
        ResponseEntity<String> responseEntity = null;
        JSONObject jsonObject = null;
        try {
            responseEntity = restTemplate.postForEntity(configService.getConfigValue(CompanyEnum.LIBERTY, "tokenUrl"), requestEntity, String.class);
            jsonObject = JSONObject.parseObject(responseEntity.getBody());
            log.info("刷新token返回:{}", jsonObject);
        } catch (HttpClientErrorException e) {
            log.info("刷新token失败:{}", e.getMessage());
            libertyToken = getToken(code);
            log.info("重新获取token:{}", libertyToken);
        }
        //返回值

        //更新token信息
        if (ObjectUtil.isNotEmpty(jsonObject)) {
            LibertyToken libertyToken1 = JSON.toJavaObject(jsonObject, LibertyToken.class);
            libertyToken.setAccessToken(libertyToken1.getAccessToken());
            libertyToken.setExpiresIn(libertyToken1.getExpiresIn());
            libertyToken.setRefreshToken(libertyToken1.getRefreshToken());
            libertyToken.setScope(libertyToken1.getScope());
            libertyToken.setTokenType(libertyToken1.getTokenType());
            libertyToken.setCreateTime(DateUtil.format(DateUtil.date(), "yyyy-MM-dd"));
        }
        mapper.updateByPrimaryKeySelective(libertyToken);
        //返回
        return libertyToken;
    }
}

